package com.dbflow5.query;

import com.dbflow5.adapter.RetrievalAdapter;
import com.dbflow5.adapter.queriable.ListModelLoader;
import com.dbflow5.adapter.queriable.SingleModelLoader;
import com.dbflow5.config.FlowLog;
import com.dbflow5.config.FlowManager;
import com.dbflow5.database.DatabaseStatement;
import com.dbflow5.database.DatabaseWrapper;
import com.dbflow5.query.list.FlowCursorList;
import com.dbflow5.query.list.FlowQueryList;
import com.dbflow5.sql.Query;
import ohos.eventhandler.EventHandler;

import java.util.List;

/**
 * Description: Provides a base implementation of [ModelQueriable] to simplify a lot of code. It provides the
 * default implementation for convenience.
 */
public abstract class BaseModelQueriable<TModel> extends BaseQueriable<TModel> implements ModelQueriable<TModel>, Query {

    private RetrievalAdapter<TModel> retrievalAdapter;

    private boolean cachingEnabled = true;

    private ListModelLoader<TModel> _cacheListModelLoader = null;

    protected ListModelLoader<TModel> listModelLoader() {
        if (cachingEnabled) {
            return retrievalAdapter.getListModelLoader();
        } else {
            return retrievalAdapter.getNonCacheableListModelLoader();
        }
    }

    protected SingleModelLoader<TModel> singleModelLoader() {
        if (cachingEnabled) {
            return retrievalAdapter.getSingleModelLoader();
        } else {
            return retrievalAdapter.getNonCacheableSingleModelLoader();
        }
    }

    protected BaseModelQueriable(Class<TModel> table){
        super(table);
        retrievalAdapter = FlowManager.getRetrievalAdapter(table);
    }

    @Override
    public BaseModelQueriable<TModel> disableCaching() {
        cachingEnabled = false;
        return this;
    }

    @Override
    public List<TModel> queryList(DatabaseWrapper databaseWrapper) {
        String query = getQuery();
        FlowLog.log(FlowLog.Level.V, "Executing query: " + query);
        return listModelLoader().load(databaseWrapper, query);
    }

    @Override
    public TModel querySingle(DatabaseWrapper databaseWrapper) {
        String query = getQuery();
        FlowLog.log(FlowLog.Level.V, "Executing query: "+query);
        return singleModelLoader().load(databaseWrapper, query);
    }

    @Override
    public FlowCursorList<TModel> cursorList(DatabaseWrapper databaseWrapper) {
        return new FlowCursorList.Builder<>(this, databaseWrapper).build();
    }

    @Override
    public FlowQueryList<TModel> flowQueryList(DatabaseWrapper databaseWrapper) {
        return new FlowQueryList.Builder<>(this, databaseWrapper, null).build();
    }

    @Override
    public long executeUpdateDelete(DatabaseWrapper databaseWrapper) {
        DatabaseStatement databaseStatement = compileStatement(databaseWrapper);
        return databaseStatement.executeUpdateDelete();
    }

    @Override
    public <QueryClass> List<QueryClass> queryCustomList(Class<QueryClass> queryModelClass, DatabaseWrapper databaseWrapper) {
        String query = getQuery();
        FlowLog.log(FlowLog.Level.V, "Executing query: "+query);
        return getListQueryModelLoader(queryModelClass).load(databaseWrapper, query);
    }

    @Override
    public <QueryClass> QueryClass queryCustomSingle(Class<QueryClass> queryModelClass, DatabaseWrapper databaseWrapper) {
        String query = getQuery();
        FlowLog.log(FlowLog.Level.V, "Executing query: "+query);
        return getSingleQueryModelLoader(queryModelClass).load(databaseWrapper, query);
    }


    protected <T> ListModelLoader<T> getListQueryModelLoader(Class<T> table) {
        if (cachingEnabled) {
            return FlowManager.retrievalAdapter(table).getListModelLoader();
        } else {
            return FlowManager.retrievalAdapter(table).getNonCacheableListModelLoader();
        }
    }

    protected <T> SingleModelLoader<T> getSingleQueryModelLoader(Class<T> table) {
        if (cachingEnabled) {
            return FlowManager.retrievalAdapter(table).getSingleModelLoader();
        } else {
            return FlowManager.retrievalAdapter(table).getNonCacheableSingleModelLoader();
        }
    }

    /**
     * Constructs a flowQueryList allowing a custom [Handler].
     *
     * @param modelQueriable modelQueriable
     * @param databaseWrapper databaseWrapper
     * @param refreshHandler refreshHandler
     * @param <T> T
     * @return new FlowQueryList.Builder<>(modelQueriable, databaseWrapper, refreshHandler).build(
     */
    public static <T> FlowQueryList<T> flowQueryList( ModelQueriable<T> modelQueriable, DatabaseWrapper databaseWrapper, EventHandler refreshHandler) {
        return new FlowQueryList.Builder<>(modelQueriable, databaseWrapper, refreshHandler).build();
    }

}

